Coding4 - 📘 User Authentication
🧠 What You’ll Learn
In this lesson, you’ll learn how to:
- Create a
User
model - Secure passwords using hashing
- Authenticate users with JSON Web Tokens (JWT)
- Build signup, login, and logout routes
🛠️ Step 1: Install Required Packages
In your terminal, run:
npm install bcryptjs jsonwebtoken
npm install --save-dev @types/bcryptjs @types/jsonwebtoken
Why?
bcryptjs
will hash passwordsjsonwebtoken
will create and verify login tokens
🧱 Step 2: Create the User Model
File: src/model/user.model.ts
import mongoose, { Schema, Document } from 'mongoose';
import bcrypt from 'bcryptjs';
// User interface for TypeScript
export interface IUser extends Document {
name: string;
email: string;
password: string;
comparePassword: (inputPassword: string) => Promise<boolean>;
}
// Define the user schema
const UserSchema: Schema<IUser> = new Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
});
// Automatically hash the password before saving
UserSchema.pre<IUser>('save', async function (next) {
if (!this.isModified('password')) return next(); // only hash if modified
this.password = await bcrypt.hash(this.password, 10); // hash the password
next();
});
// Method to compare plain password with hashed one
UserSchema.methods.comparePassword = async function (inputPassword: string) {
return bcrypt.compare(inputPassword, this.password);
};
export default mongoose.model<IUser>('User', UserSchema);
Explanation: This model defines how users are stored in the database and ensures passwords are securely hashed.
🔐 Step 3: Build the Authentication Controller
File: src/controller/auth.controller.ts
import { Request, Response } from 'express';
import User from '../model/user.model';
import jwt from 'jsonwebtoken';
// Function to create a JWT token
const generateToken = (id: string) => {
return jwt.sign({ id }, process.env.JWT_SECRET as string, {
expiresIn: '1d', // valid for 1 day
});
};
// User signup controller
export const signup = async (req: Request, res: Response) => {
const { name, email, password } = req.body;
try {
const existingUser = await User.findOne({ email });
if (existingUser)
return res.status(400).json({ message: 'User already exists' });
const user = await User.create({ name, email, password });
const token = generateToken(user._id.toString());
res.status(201).json({
token,
user: { id: user._id, name: user.name, email: user.email },
});
} catch (error) {
res.status(500).json({ message: 'Signup failed', error });
}
};
// User login controller
export const login = async (req: Request, res: Response) => {
const { email, password } = req.body;
try {
const user = await User.findOne({ email });
// Check if user exists and password is valid
if (!user || !(await user.comparePassword(password))) {
return res.status(401).json({ message: 'Invalid credentials' });
}
const token = generateToken(user._id.toString());
res.json({
token,
user: { id: user._id, name: user.name, email: user.email },
});
} catch (error) {
res.status(500).json({ message: 'Login failed', error });
}
};
// User logout controller (token stays on client)
export const logout = (_req: Request, res: Response) => {
res.json({ message: 'Logged out successfully (client should delete token)' });
};
Explanation: This handles:
- 🔐 Signup: creates a new user and returns a token
- 🔑 Login: verifies credentials and returns a token
- 🚪 Logout: clears session (from client)
🛣️ Step 4: Create the Auth Routes
File: src/routes/auth.routes.ts
import { Router } from 'express';
import { signup, login, logout } from '../controller/auth.controller';
const router = Router();
router.post('/signup', signup); // register
router.post('/login', login); // login
router.get('/logout', logout); // logout
export default router;
Explanation:
This connects the controller functions to actual URLs. Now you can use /api/auth/signup
, etc.
🌐 Step 5: Use Routes in the App
File: src/app.ts
import express from 'express';
import dotenv from 'dotenv';
import connectDB from './dbconnect';
import authRoutes from './routes/auth.routes';
dotenv.config(); // load env variables
const app = express();
const PORT = process.env.PORT || 5000;
// Connect to MongoDB
connectDB(process.env.MONGO_URI as string);
// Middleware to parse JSON
app.use(express.json());
// Register our auth API routes
app.use('/api/auth', authRoutes);
app.get('/', (_req, res) => res.send('API is running...'));
app.listen(PORT, () => {
console.log(`🚀 Server running on port ${PORT}`);
});
Explanation: This is your main app file that starts the server and includes the routes for authentication.
🔑 Step 6: Add Environment Variables
File: .env
PORT=5000
MONGO_URI=mongodb://localhost:27017/your-db-name
JWT_SECRET=yourStrongSecretHere
Explanation: Keep sensitive data like database URI and secret keys out of your codebase.
✅ Final Result
Your auth routes are now live!
Method | Endpoint | What it does |
---|---|---|
POST | /api/auth/signup | Register new user |
POST | /api/auth/login | Login existing user |
GET | /api/auth/logout | Logout (client-side) |